#ifndef _ARF_PARSER_H_
#define _ARF_PARSER_H_

#include <string>
#include <iostream>
#include <vector>
#include <sstream>

//=================================================================
// Parser
//=================================================================

class Parser
{
public:
	class Node;
	typedef Node* hNode;
	class Function;
	class Operator;
	class Number;
	class Variable;

private:
	Parser::hNode m_root;
	std::vector<Variable*> m_variables;
	std::vector<double> m_variables_values;
	std::string m_expression;

private:
	Parser::hNode get_next(int& i, const std::string st, bool prev_is_number) const;
	bool is_operator (const char* c) const;
	bool is_function (const char* c) const;
	bool is_number   (const char* c) const;
	bool is_variable (const char* c) const;
	Parser::hNode get_operator(int& i, const std::string& st) const;
	Parser::hNode get_function(int& i, const std::string& st) const;
	Parser::hNode get_number  (int& i, const std::string& st) const;
	Parser::hNode get_variable(int& i, const std::string& st) const;
	void tree(std::vector<Parser::hNode>& v, int l, int r, Parser::hNode& root);
	bool have_one_sequence(const std::vector<Parser::hNode>& v, int l, int r) const;
	void init();
	void clear();

public:
	Parser(std::string expression);
	Parser(const Parser&);
	Parser& operator = (const Parser&);
	void plot_tree() const;
	std::string to_string() const;
	double operator()(std::vector<double> param = std::vector<double>());

	~Parser(void);
};

//=================================================================
// Node
//=================================================================

class Parser::Node
{
public:
	virtual double evaluate() const = 0;
	virtual void print(std::ostream& os) const = 0;
	virtual void print_tree(int h) const = 0;
	virtual int precedence() const = 0;
	virtual std::string to_string() const = 0;
	virtual std::string to_string_exp() const = 0;
	virtual int h() const = 0;
	virtual int lower_precedence() const = 0;
};

inline std::ostream& operator << (std::ostream& os, const Parser::Node& node)
{
	node.print(os);
	return os;
}

//=================================================================
// Function
//=================================================================

class Parser::Function : public Parser::Node
{
	Parser::hNode m_parameter;
	std::string m_function;
public:
	Function(std::string function, Parser::hNode parameter = 0);
	~Function();
	double evaluate() const;
	Parser::hNode& parameter();
	void print(std::ostream& os) const;
	void print_tree(int h) const;
	int precedence() const;
	std::string to_string() const;
	std::string to_string_exp() const;
	int h() const;
	int lower_precedence() const;
};

//=================================================================
// Operator
//=================================================================

class Parser::Operator : public Parser::Node
{
	Parser::hNode m_left;
	Parser::hNode m_right;
	std::string m_operator;
public:
	Operator(const std::string& op, Parser::hNode left=0, Parser::hNode right=0);
	~Operator();
	double evaluate() const;
	Parser::hNode& left();
	Parser::hNode& right();
	void print(std::ostream& os) const;
	int precedence() const;
	void print_tree(int h) const;
	std::string to_string() const;
	std::string to_string_exp() const;
	int h() const;
	int lower_precedence() const;
};

//=================================================================
// Number
//=================================================================

class Parser::Number : public Parser::Node
{
	double m_value;
public:
	Number(double n = 0);
	double evaluate() const;
	void print(std::ostream& os) const;
	int precedence() const;
	void print_tree(int h) const;
	std::string to_string() const;
	std::string to_string_exp() const;
	int h() const;
	int lower_precedence() const;
};

//=================================================================
// Variable
//=================================================================

class Parser::Variable : public Parser::Node
{
	double* m_value;
	std::string m_variable;
	int m_index;
public:
	Variable(std::string v, double *n = 0);
	double evaluate() const;
	void print(std::ostream& os) const;
	int precedence() const;
	void print_tree(int h) const;
	std::string to_string() const;
	std::string to_string_exp() const;
	int h() const;
	int lower_precedence() const;
	int variable_index() const;
	void pointer_to_value(double *v);
};

#endif
